# -*- coding: utf-8 -*-

import copy
import time
import requests
import json
from urllib import urlencode
from urlparse import urljoin
import logging
logger = logging.getLogger('bt_server')

from .exceptions import InnerAPIError


class InnerServices(object):
    """
        用于服务间内部调用    
    """

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(InnerServices, cls).__new__(cls, *args, **kwargs)
        return cls._instance

    def __init__(self, settings=None):
        super(InnerServices, self).__init__()
        self._settings = None
        # server token
        self._server_token = ''
        self._server_token_type = ''
        self._server_token_expires = 0
        if settings:
            self.settings = settings

    @property
    def settings(self):
        return self._settings

    @settings.setter
    def settings(self, value):
        self._settings = copy.deepcopy(value)

    @classmethod
    def inner(cls, target_cls):
        """
            将一个 InnerAPI 派生类变为InnerServices的一个API方法
        """
        if not hasattr(cls, '_instance'):
            cls()
        api = target_cls(cls._instance)
        setattr(cls._instance, target_cls.__name__, api)

    # def get_server_token(self):
    #     """获取服务的token:
    #         如果已获取的token已过期或小于30s后过期, 则重新申请token
    #     """
    #     # 已有的服务器token过期,则重新申请一个(预留30s)
    #     cur_time = int(time.time())
    #     if (cur_time + 30) > self._server_token_expires:
    #         """申请服务token
    #             access_token 解析后为:
    #             {
    #                 u'scope': [u'server'],
    #                 u'jti': u'3bea9405-3d0f-48a2-b869-9bed8a906aa2',
    #                 u'client_id': u'message',
    #                 u'exp': 1477523370
    #             }
    #         """
    #         url = 'http://{server_name}:{server_passwd}@{gateway_addr}:{gateway_port}/api/account/oauth/token'
    #         rv = requests.post(
    #             url=self.format_url(
    #                 url, {
    #                     'server_name': self.server_name,
    #                     'server_passwd': self.server_passwd,
    #                 }),
    #             data='grant_type=client_credentials&scope=server',
    #             headers={'Content-Type': 'application/x-www-form-urlencoded'})
    #         if rv.status_code != 200:
    #             raise InnerAPIError(rv.status_code, rv.text)
    #         data = rv.json()
    #         self._server_token = data['access_token']
    #         self._server_token_type = data['token_type']
    #         self._server_token_expires = int(data['expires_in']) + int(
    #             time.time())
    #     return {
    #         'access_token': self._server_token,
    #         'token_type': self._server_token_type,
    #         'expires_in': self._server_token_expires
    #     }


class InnerAPI(object):
    """
        Base Inner API    
    """

    def __init__(self, inner_services):
        if not hasattr(self, 'url'):
            raise InnerAPIError(
                'InnerAPI class "{}" need has a url attr!'.format(
                    self.__class__.__name__))
        self._inner_services = inner_services

    def generate_url(self, extra_path=''):
        url = self.url
        if extra_path != '':
            url = urljoin(url + '/', str(extra_path))
        return url

    # def generate_authorization(self, token='', token_type=''):
    #     """生成http头->'Authorization'"""
    #     if not token or not token_type:
    #         token_info = self._inner_services.get_server_token()
    #         return '{token_type} {access_token}'.format(**token_info)
    #     else:
    #         return '{token_type} {access_token}'.format(
    #             token_type=token_type, access_token=token)

    def get_one(self, id, headers={}, token='', token_type=''):
        """Get One"""

        url = self.generate_url(id)
        _headers = {
            # 'Authorization': self.generate_authorization(token, token_type)
        }
        _headers.update(headers)
        headers = _headers
        logger.debug('Get %s' % url)
        rv = requests.get(url=url, headers=headers)
        # if rv.status_code == 404:
        #     return None
        if rv.status_code != 200:
            raise InnerAPIError(rv.status_code, rv.text)
        try:
            return rv.json()
        except:
            return rv.text

    def get_few(self, query='', headers={}, token='', token_type=''):
        """Get Few"""

        if not isinstance(query, str):
            query = urlencode(query)
        if query.startswith('?'):
            query = query[1:]
        url = self.generate_url() + '?' + query
        _headers = {
            # 'Authorization': self.generate_authorization(token, token_type)
        }
        _headers.update(headers)
        headers = _headers
        logger.debug('Get %s' % url)
        rv = requests.get(url=url, headers=headers)
        if rv.status_code != 200:
            raise InnerAPIError(rv.status_code, rv.text)
        try:
            return rv.json()
        except:
            return rv.text

    def create(self, data, headers={}, token='', token_type=''):
        """Create Instance"""

        url = self.generate_url()
        _headers = {
            # 'Authorization': self.generate_authorization(token, token_type),
            'Content-Type': 'application/json'
        }
        _headers.update(headers)
        headers = _headers
        data_data = ''
        json_data = {}
        if headers['Content-Type'] == 'application/x-www-form-urlencoded':
            # From 格式
            if not isinstance(data, str):
                data = urlencode(data)
            data_data = data
        # Json 格式
        elif headers['Content-Type'] == 'application/json':
            if isinstance(data, str):
                data = json.loads(data)
            json_data = data
        else:
            data_data = data
        logger.debug('Post %s' % url)
        rv = requests.post(
            url=url, data=data_data, json=json_data, headers=headers)
        if rv.status_code not in (200, 201):
            raise InnerAPIError(rv.status_code, rv.text)
        try:
            return rv.json()
        except:
            return rv.text

    def modify(self, id, data, headers={}, token='', token_type=''):
        """Modify Instance"""

        url = self.generate_url(id)
        _headers = {
            # 'Authorization': self.generate_authorization(token, token_type),
            'Content-Type': 'application/json'
        }
        _headers.update(headers)
        headers = _headers
        data_data = ''
        json_data = {}
        if headers['Content-Type'] == 'application/x-www-form-urlencoded':
            # From 格式
            if not isinstance(data, str):
                data = urlencode(data)
            data_data = data
        # Json 格式
        elif headers['Content-Type'] == 'application/json':
            if isinstance(data, str):
                data = json.loads(data)
            json_data = data
        else:
            data_data = data
        logger.debug('Put %s' % url)
        rv = requests.put(
            url=url, data=data_data, json=json_data, headers=headers)
        if rv.status_code != 200:
            raise InnerAPIError(rv.status_code, rv.text)
        try:
            return rv.json()
        except:
            return rv.text

    def delete(self, id, headers={}, token='', token_type=''):
        """Delete Instance"""

        url = self.generate_url(id)
        _headers = {
            # 'Authorization': self.generate_authorization(token, token_type)
        }
        _headers.update(headers)
        headers = _headers
        logger.debug('Delete %s' % url)
        rv = requests.delete(url=url, headers=headers)
        if rv.status_code not in (200, 204):
            raise InnerAPIError(rv.status_code, rv.text)
        try:
            return rv.json()
        except:
            return rv.text


""""
# --- for test ---
@InnerServices.inner
class EmployeeAPI(InnerAPI):
    url = 'http://{gateway_addr}:{gateway_port}/api/account/employees'

inner_services = InnerServices()
inner_services.init_app('')

employee = inner_services.EmployeeAPI.create({
    "mobile": "13800138000",
    "name": "asdfefe",
    "gender": 1,
    "idNum": "510123456789012345",
    "type": 1,
    "enabled": True,
})
print inner_services.EmployeeAPI.get_one(employee['id'])
print inner_services.EmployeeAPI.get_few()
print inner_services.EmployeeAPI.modify(employee['id'], {"mobile": "13800138777"})
print inner_services.EmployeeAPI.delete(employee['id'])
"""
